package db0

import (
	"log"
	"sync"

	"github.com/samber/lo"
	// go: found gorm.io/driver/sqlite in gorm.io/driver/sqlite v1.6.0
	"gorm.io/driver/sqlite"
	"gorm.io/gorm"
	"gorm.io/gorm/logger"
	_ "modernc.org/sqlite"
	// _ "modernc.org/sqlite/driver"
	// _ "github.com/mattn/go-sqlite3" // CGO 驱动
	// _ "modernc.org/sqlite" // 纯 Go 驱动
)

/*
访问较慢
https://gorm.io/zh_CN/docs/index.html
访问较快
https://learnku.com/docs/gorm/v2/index/9728

go get -u gorm.io/gorm
go get -u gorm.io/driver/sqlite
*/

var (
	once0 sync.Once
	store DbStore
)

// 分页查询
type PageDatas[T any] struct {
	Datas []T   `json:"datas"`
	Total int64 `json:"total"`
}

/*
`DbStore`: database仓库
`mPath`: mapPath, path集合
*/
type DbStore struct {
	mPath map[string]*gorm.DB
	// mName map[string]string
}

/*
panic: assignment to entry in nil map
遇到BUG了，如上
`NewDbStore`不能被多个方法调用, 否则产生的第二个`store`与第一个`store`不是同一个对象
`store` 变量应该在方法外面定义, 保证多次调用获取的是同一个对象
*/
func NewDbStore() DbStore {
	once0.Do(func() {
		store = DbStore{
			mPath: make(map[string]*gorm.DB),
		}
	})
	return store
}

/*
receiver name should be a reflection of its identity;
don't use generic names such as "this" or "self" (ST1006)go-staticcheck
self -> me
*/
func (me DbStore) GetByPath(path string) (db *gorm.DB, err error) {
	log.Println("db path: ", path)
	// 高版本的`lo`才有`HasKey`方法, 低版本可用 `Keys` + `Count` 代替 : `if lo.Count(lo.Keys(me.mPath), path) > 0 {`
	if lo.HasKey(me.mPath, path) {
		db = me.mPath[path]
		return
	}

	db, err = gorm.Open(sqlite.Open(path), &gorm.Config{
		// CreateBatchSize: 100,
		// 【生产环境】避免慢查询输出到控制台上 `logger.Error`
		// 2025/07/09 20:05:44 D:/s_code/go/hifini_music/search_tool/src/db/db_main.go:75 SLOW SQL >= 200ms
		// 这种错误也不要输出到控制台 `logger.Silent`
		// 2025/07/09 20:20:06 D:/s_code/go/hifini_music/search_tool/src/db/db_dict.go:31 record not found
		Logger: logger.Default.LogMode(logger.Error),
	})

	if err != nil {
		log.Fatalf("failed to connect database : %s\n", path)
		return
	}

	// 缓存起来
	// panic: assignment to entry in nil map
	me.mPath[path] = db

	return
}
